From 0773e2a340786190f61b1a9f3f9bb651ba7a377e Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 6 Apr 2006 09:39:30 +0100 Subject: [PATCH] Fix a problem that was caused by recent changes to the xenbus's behavior that cause the .remove function not to be called anymore during suspend. Due to that the driver allocated one more interrupt on every suspend/resume cycle. Otherwise some code reformatting, cleanups and improvements on allocation and freeing of data structure. Signed-off-by: Stefan Berger --- .../drivers/xen/tpmfront/tpmfront.c | 121 ++++++++++++------ 1 file changed, 79 insertions(+), 42 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c index 03a2ab9ea0..53ccf66b82 100644 --- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c @@ -65,14 +65,18 @@ static irqreturn_t tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs); static void tpmif_rx_action(unsigned long unused); -static void tpmif_connect(struct tpm_private *tp, domid_t domid); +static int tpmif_connect(struct xenbus_device *dev, + struct tpm_private *tp, + domid_t domid); static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0); -static int tpm_allocate_buffers(struct tpm_private *tp); +static int tpmif_allocate_tx_buffers(struct tpm_private *tp); +static void tpmif_free_tx_buffers(struct tpm_private *tp); static void tpmif_set_connected_state(struct tpm_private *tp, u8 newstate); static int tpm_xmit(struct tpm_private *tp, const u8 * buf, size_t count, int userbuffer, void *remember); +static void destroy_tpmring(struct tpm_private *tp); #define DPRINTK(fmt, args...) \ pr_debug("xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args) @@ -81,6 +85,8 @@ static int tpm_xmit(struct tpm_private *tp, #define WPRINTK(fmt, args...) \ printk(KERN_WARNING "xen_tpm_fr: " fmt, ##args) +#define GRANT_INVALID_REF 0 + static inline int tx_buffer_copy(struct tx_buffer *txb, const u8 * src, int len, @@ -119,6 +125,14 @@ static inline struct tx_buffer *tx_buffer_alloc(void) } +static inline void tx_buffer_free(struct tx_buffer *txb) +{ + if (txb) { + free_page((long)txb->data); + kfree(txb); + } +} + /************************************************************** Utility function for the tpm_private structure **************************************************************/ @@ -128,23 +142,29 @@ static inline void tpm_private_init(struct tpm_private *tp) init_waitqueue_head(&tp->wait_q); } +static inline void tpm_private_free(void) +{ + tpmif_free_tx_buffers(my_priv); + kfree(my_priv); + my_priv = NULL; +} + static struct tpm_private *tpm_private_get(void) { + int err; if (!my_priv) { my_priv = kzalloc(sizeof(struct tpm_private), GFP_KERNEL); if (my_priv) { tpm_private_init(my_priv); + err = tpmif_allocate_tx_buffers(my_priv); + if (err < 0) { + tpm_private_free(); + } } } return my_priv; } -static inline void tpm_private_free(void) -{ - kfree(my_priv); - my_priv = NULL; -} - /************************************************************** The interface to let the tpm plugin register its callback @@ -233,6 +253,8 @@ static int setup_tpmring(struct xenbus_device *dev, tpmif_tx_interface_t *sring; int err; + tp->ring_ref = GRANT_INVALID_REF; + sring = (void *)__get_free_page(GFP_KERNEL); if (!sring) { xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); @@ -240,8 +262,6 @@ static int setup_tpmring(struct xenbus_device *dev, } tp->tx = sring; - tpm_allocate_buffers(tp); - err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx)); if (err < 0) { free_page((unsigned long)sring); @@ -251,14 +271,13 @@ static int setup_tpmring(struct xenbus_device *dev, } tp->ring_ref = err; - err = xenbus_alloc_evtchn(dev, &tp->evtchn); + err = tpmif_connect(dev, tp, dev->otherend_id); if (err) goto fail; - tpmif_connect(tp, dev->otherend_id); - return 0; fail: + destroy_tpmring(tp); return err; } @@ -266,14 +285,17 @@ fail: static void destroy_tpmring(struct tpm_private *tp) { tpmif_set_connected_state(tp, 0); - if (tp->tx != NULL) { + + if (tp->ring_ref != GRANT_INVALID_REF) { gnttab_end_foreign_access(tp->ring_ref, 0, (unsigned long)tp->tx); + tp->ring_ref = GRANT_INVALID_REF; tp->tx = NULL; } if (tp->irq) - unbind_from_irqhandler(tp->irq, NULL); + unbind_from_irqhandler(tp->irq, tp); + tp->evtchn = tp->irq = 0; } @@ -377,6 +399,9 @@ static int tpmfront_probe(struct xenbus_device *dev, int handle; struct tpm_private *tp = tpm_private_get(); + if (!tp) + return -ENOMEM; + err = xenbus_scanf(XBT_NULL, dev->nodename, "handle", "%i", &handle); if (XENBUS_EXIST_ERR(err)) @@ -402,15 +427,14 @@ static int tpmfront_probe(struct xenbus_device *dev, static int tpmfront_remove(struct xenbus_device *dev) { - struct tpm_private *tp = dev->data; + struct tpm_private *tp = (struct tpm_private *)dev->data; destroy_tpmring(tp); return 0; } -static int -tpmfront_suspend(struct xenbus_device *dev) +static int tpmfront_suspend(struct xenbus_device *dev) { - struct tpm_private *tp = dev->data; + struct tpm_private *tp = (struct tpm_private *)dev->data; u32 ctr; /* lock, so no app can send */ @@ -437,29 +461,35 @@ tpmfront_suspend(struct xenbus_device *dev) return 0; } -static int -tpmfront_resume(struct xenbus_device *dev) +static int tpmfront_resume(struct xenbus_device *dev) { - struct tpm_private *tp = dev->data; + struct tpm_private *tp = (struct tpm_private *)dev->data; + destroy_tpmring(tp); return talk_to_backend(dev, tp); } -static void -tpmif_connect(struct tpm_private *tp, domid_t domid) +static int tpmif_connect(struct xenbus_device *dev, + struct tpm_private *tp, + domid_t domid) { int err; tp->backend_id = domid; + err = xenbus_alloc_evtchn(dev, &tp->evtchn); + if (err) + return err; + err = bind_evtchn_to_irqhandler(tp->evtchn, tpmif_int, SA_SAMPLE_RANDOM, "tpmif", tp); if (err <= 0) { WPRINTK("bind_evtchn_to_irqhandler failed (err=%d)\n", err); - return; + return err; } tp->irq = err; + return 0; } static struct xenbus_device_id tpmfront_ids[] = { @@ -488,19 +518,30 @@ static void __exit exit_tpm_xenbus(void) xenbus_unregister_driver(&tpmfront); } - -static int -tpm_allocate_buffers(struct tpm_private *tp) +static int tpmif_allocate_tx_buffers(struct tpm_private *tp) { unsigned int i; - for (i = 0; i < TPMIF_TX_RING_SIZE; i++) + for (i = 0; i < TPMIF_TX_RING_SIZE; i++) { tp->tx_buffers[i] = tx_buffer_alloc(); - return 1; + if (!tp->tx_buffers[i]) { + tpmif_free_tx_buffers(tp); + return -ENOMEM; + } + } + return 0; +} + +static void tpmif_free_tx_buffers(struct tpm_private *tp) +{ + unsigned int i; + + for (i = 0; i < TPMIF_TX_RING_SIZE; i++) { + tx_buffer_free(tp->tx_buffers[i]); + } } -static void -tpmif_rx_action(unsigned long priv) +static void tpmif_rx_action(unsigned long priv) { struct tpm_private *tp = (struct tpm_private *)priv; @@ -545,8 +586,7 @@ exit: } -static irqreturn_t -tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs) +static irqreturn_t tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs) { struct tpm_private *tp = tpm_priv; unsigned long flags; @@ -560,10 +600,9 @@ tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs) } -static int -tpm_xmit(struct tpm_private *tp, - const u8 * buf, size_t count, int isuserbuffer, - void *remember) +static int tpm_xmit(struct tpm_private *tp, + const u8 * buf, size_t count, int isuserbuffer, + void *remember) { tpmif_tx_request_t *tx; TPMIF_RING_IDX i; @@ -693,8 +732,7 @@ static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected) * ================================================================= */ -static int __init -tpmif_init(void) +static int __init tpmif_init(void) { IPRINTK("Initialising the vTPM driver.\n"); if ( gnttab_alloc_grant_references ( TPMIF_TX_RING_SIZE, @@ -709,8 +747,7 @@ tpmif_init(void) module_init(tpmif_init); -static void __exit -tpmif_exit(void) +static void __exit tpmif_exit(void) { exit_tpm_xenbus(); gnttab_free_grant_references(gref_head); -- 2.30.2